package com.github.livebase.plugins;

import android.util.ArrayMap;

import com.github.livebase.bean.ChannelGroup;
import com.github.livebase.bean.IjkCodec;
import com.github.livebase.event.EventBus;
import com.github.livebase.event.EventListener;
import com.github.livebase.event.SimpleEventBus;
import com.github.livebase.log.FileLogger;
import com.github.livebase.log.Logger;
import com.github.livebase.storage.LocalStorage;
import com.github.livebase.storage.PluginsStorage;
import com.github.livebase.util.LiveContext;
import com.github.livebase.util.base.ArraysUtil;
import com.github.livebase.util.base.CollectionsUtil;
import com.github.livebase.util.base.ObjectsUtil;

import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * @ClassName PluginFactory
 * @description:
 * @author: biao532
 * @create: 2023-12-30 21:59
 * @Version 1.0
 **/
public class PluginFactory {
    private LiveContext context;
    private int logLevel;
    private Map<String, RegisterInfo> registerInfoMap;
    private Logger logger;
    public PluginFactory(LiveContext context, int logLevel) {
        this.context = context;
        this.registerInfoMap = new ArrayMap<>();
        this.logLevel = logLevel;
        this.logger = new FileLogger(LiveContext.getLogFile(this.context, "plugin.log"), logLevel);
    }

    public int getLogLevel() {
        return logLevel;
    }

    public <T> T getOrDefault(String key, T t) {
        return ObjectsUtil.getOrDefault(get(key), t);
    }

    public<T> T get(String key) {
        try {
            key = key.toLowerCase(Locale.ROOT);
            RegisterInfo info = registerInfoMap.get(key);
            logger.debug("PluginFactory", "get[{}] info[{}] maps={}", key, info, registerInfoMap);

            if (info == null) {
                return null;
            }
            Register<T> o = (Register<T>) info.getObject();
            return o.register(this.context, info.getContext());
        }
        catch (IllegalAccessException | InstantiationException | AbstractMethodError e) {
            logger.warn("PluginFactory", e,"an error occurred during get Object for key " + key);
        }
        return null;
    }
    public List<IjkCodec> getIjkCodec() {
        return getOrDefault("ijkCodec", ObjectsUtil.Empty.LIST);
    }

    public List<ChannelGroup> getGroups() {
        return getOrDefault("channel", ObjectsUtil.Empty.LIST);
    }

    public File getPluginsCacheDir() {
        File file = context.getFileStreamPath("dexCache");
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    public void register(RegisterInfo info) {
        RegisterInfo r = registerInfoMap.get(info.getKey());
        try {
            if (!ArraysUtil.isEmpty(info.getBusEvent()) && EventListener.class.isAssignableFrom(info.getClazz())) {
                EventBus eventBus = SimpleEventBus.getDefault();
                // 相同key保留后者，之前的取消注册
                for (String event : info.getBusEvent()) {
                    if (r != null) {
                        eventBus.unregister(event, (EventListener) r.getObject());
                    }
                    eventBus.register(event, (EventListener) info.getObject(), true);
                }
                // 初始化listener 且 不加入map
                if (info.isOnlyListener()) {
                    ((Register)info.getObject()).register(this.context, info.getContext());
                }
            }
        } catch (IllegalAccessException | InstantiationException e) {
            logger.warn("PluginFactory", e, "fail to register eventbus for class[{}}]", info.getClazz());
            return;
        }
        if (!info.isOnlyListener()) {
            registerInfoMap.put(info.getKey().toLowerCase(Locale.ROOT), info);
        }
    }
    public void register(List<RegisterInfo> infos) {
        CollectionsUtil.foreach(infos, this::register);
    }

    protected Logger newLogger(PluginContext context) {
        return logger;
    }
    protected LocalStorage newStorage(PluginContext context) {
        return new PluginsStorage(context, this.context.getLiveDatabaseHelper());
    }
}
